/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.view;

import com.flexengine.config.Configuration;
import com.flexengine.config.ConfigurationManager;
import com.flexengine.cursor.CursorManager;
import com.flexengine.engine.FlexEngine;
import com.flexengine.scene.GameScene;
import com.flexengine.scene.SceneManager;
import com.flexengine.utils.FontManager;
import com.flexengine.logger.Logger;
import com.flexengine.language.LanguageMacro;
import com.flexengine.language.LanguageManager;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferStrategy;
import java.text.DecimalFormat;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class Renderer {
    
    // -- General fields...
    private RendererType renderType;
    private Graphics     graphics;
    private boolean      clearBackground;
    
    // -- General fields...
    private final DecimalFormat decimalFormat;
    private GameWindow    gWindow;
    
    // -- OpenGL fields...
    
    // -- DirectX fields...
    
    public Renderer() {
        Logger.logMessage(getClass().getSimpleName()+" - Creating render...");
        this.renderType      = RendererType.RENDERER_DEFAULT;
        this.graphics        = null;
        this.decimalFormat   = new DecimalFormat("#0.00");
        this.clearBackground = true;
        Logger.logMessage(getClass().getSimpleName()+" - Render created! ["+this+"]");
    }
    
    public synchronized void initRender() {
        gWindow = GameWindow.getInstance();
        Logger.logMessage(getClass().getSimpleName()+" initRender(): Initializing render...");
        try {
            Logger.logMessage(getClass().getSimpleName()+" initRender(): RENDER_TYPE = "+getRenderType());
            switch(renderType) {
                case RENDERER_DEFAULT:
                    if( !gWindow.isFullScreen() ) {
                        gWindow.setVisible(true);
                    }
                    graphics = GraphicsJ2D.getInstance();
                    break;
                case RENDERER_OPENGL:
                    initOpenGL();
                    break;
                case RENDERER_DIRECTX:
                    String os = System.getProperty("os.name");
                    if( os.startsWith("Windows") ) {
                        initDirectX();
                    } else {
                        renderType = RendererType.RENDERER_OPENGL;
                        initOpenGL();
                    }
                    break;
            }
            Logger.logMessage(getClass().getSimpleName()+" - initRender(): graphics = "+graphics);
        }
        catch(Exception ex) {
            Logger.logError(getClass().getSimpleName()+": "+ex);
        }
    }
    
    private synchronized void initOpenGL() {
        Logger.logMessage(getClass().getSimpleName()+" - initOpenGL: Initializing OpenGL!");
        try {
        } catch(Exception e) {
            Logger.logError(getClass().getSimpleName()+" - initOpenGL | ERROR: "+e);
            System.exit(0);
        }
        Logger.logMessage(getClass().getSimpleName()+" - initOpenGL: OpenGL initialized!");
    }
    
    private synchronized void initDirectX() {
        // -- do nothing yet...
        Logger.logWarning("Renderer - initDirectX: This render's method is not available yet!");
        System.exit(0);
    }
    
    public synchronized void update() {
        if( graphics!=null ) {
            graphics.update();
        }
    }
    
    private final Font fpsFont = FontManager.getFont("Verdana", 1, 12);
    private final Font pausedFont = FontManager.getFont("Verdana",1,32);
    
    public synchronized boolean render() {
        if( !FlexEngine.getInstance().isRunning() ) {
            return false;
        } else if( graphics==null ) {
            //Logger.logError("Renderer - render(): Graphics for renderer context is NULL!");
            return false;
        }
        // -- Set ultimate attributes...
        Configuration config = ConfigurationManager.getInstace().getDefaultConfiguration();
        if( config.isAntialising() ) {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        } else {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        }
        if( config.isTextAntialising() ) {
            graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        } else {
            graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        }
        // -- Color to clean the background... Color = [black]
        graphics.setColor(GameWindow.getInstance().getBackground());
        if( clearBackground ) {
            graphics.clear();
        }
        // ---------------------------------------------------------------------
        GameScene scene = SceneManager.getInstance().getCurrentScene();
        if( scene!=null ) {
            scene.render(graphics);
        }
        // ---------------------------------------------------------------------
        // GameWindow.getInstance().paintComponents();
        // --
        if( FlexEngine.getInstance().isPaused() ) {
            Point center = GameWindow.getInstance().getCenterPoint();
            String paused = LanguageManager.getLanguage().getValue(LanguageMacro.PAUSED);
            graphics.setFont(pausedFont);
            Rectangle2D rect = pausedFont.getStringBounds(paused, new FontRenderContext(null, true, false));
            int tmpX = (int)(center.x-rect.getWidth()/2);
            int tmpY = (int)(center.y+rect.getHeight()/2);
            //rect.setRect(tmpX, tmpY-rect.getHeight(), rect.getWidth(), rect.getHeight());
            graphics.setColor(Color.WHITE);
            //graphics.draw(rect);
            graphics.drawString(paused, tmpX, tmpY);
        }
        // -- Render the Game Cursor...
        if( CursorManager.isShowGameCursor() ) {
            graphics.draw(CursorManager.getGameCursor());
        }
        if( FlexEngine.getInstance().isShowFps() ) {
            graphics.setFont(fpsFont);
            graphics.setColor(Color.cyan);
            graphics.drawString(
                    "aFPS: "+decimalFormat.format(FlexEngine.getInstance().getAvarageFPS()), 
                    5,
                    GameWindow.getInstance().getHeight()-4);
        }
        // -- dispose...
        graphics.dispose();
        return true;
    }
    
    public synchronized boolean show() {
        try {
            switch(renderType) {
                case RENDERER_DEFAULT:
                    // -- Swap java2D buffers...
                    BufferStrategy bs = GraphicsJ2D.getInstance().getBufferStrategy();
                    if( bs!=null && !bs.contentsLost() ) {
                        bs.show();
                    }
                    break;
                case RENDERER_OPENGL:
                    // -- Swap OpenGL buffers...
                    break;
                case RENDERER_DIRECTX:
                    break;
            }
            return true;
        } catch(Exception e) {
            Logger.logError("Renderer 1.0b - show(): "+e);
            System.exit(0);
        }
        return false;
    }
    
    public synchronized Graphics getGraphics() {
        return graphics;
    }

    public void setGraphics(Graphics graphics) {
        this.graphics = graphics;
    }
    
    public void setClearBackground(boolean clearBackground) {
        this.clearBackground = clearBackground;
    }

    public boolean isClearBackground() {
        return clearBackground;
    }
    
    public RendererType getRender() {
        return renderType;
    }
    public String getRenderType() {
        switch(renderType) {
            case RENDERER_DEFAULT:
                return "["+renderType+" | RENDERER_DEFAULT]";
            case RENDERER_OPENGL:
                return "["+renderType+" | RENDERER_OPEN_GL]";
            case RENDERER_DIRECTX:
                return "["+renderType+" | RENDERER_DIRECTX]";
        }
        return "NULL";
    }
    
    public boolean changeRender(RendererType render) {
        try {
            this.renderType = render;
            return true;
        } catch(Exception e) {
        }
        return false;
    }

    @Override
    public String toString() {
        return "Renderer 1.0b - "+getRenderType();
    }
    
    private static Renderer instance;
    public static Renderer getRenderer() {
        if( instance == null ) {
            instance = new Renderer();
        }
        return instance;
    }
    
}
